#include "esp_camera.h"
#include <WiFi.h>
#include <WiFiUdp.h>
#include <SD_MMC.h>
#include <time.h>

// 摄像头引脚配置（AI-Thinker ESP32-CAM）
#define PWDN_GPIO_NUM     32
#define RESET_GPIO_NUM    -1
#define XCLK_GPIO_NUM      0
#define SIOD_GPIO_NUM     26
#define SIOC_GPIO_NUM     27
#define Y9_GPIO_NUM       35
#define Y8_GPIO_NUM       34
#define Y7_GPIO_NUM       39
#define Y6_GPIO_NUM       36
#define Y5_GPIO_NUM       21
#define Y4_GPIO_NUM       19
#define Y3_GPIO_NUM       18
#define Y2_GPIO_NUM        5
#define VSYNC_GPIO_NUM    25
#define HREF_GPIO_NUM     23
#define PCLK_GPIO_NUM     22

#define CONTROL_PIN 4
String version = "20250410-版本3";

// 新增全局变量（网页3/5/7）
#define MAX_FILES 100          // 最大保留文件数
#define MIN_FREE_SPACE 100     // 最小保留空间(MB)
unsigned long segmentStartTime = 0;  // ★ 新增分段计时变量
#define SEGMENT_DURATION 3600000      // 60分钟分段（3600000ms）
int segmentIndex = 0;          // 分段序号
String currentFileName;        // 当前文件名
unsigned long lastDeleteCheck = 0;

// 网络配置
const char* ssid = "Honor 9X";
const char* password = "12345678";
const IPAddress targetIP(192, 168, 10, 121);
const uint16_t targetPort = 12345;
const uint16_t CONTROL_PORT = 12346;

WiFiUDP udp;
WiFiUDP udpControl;

// SD卡配置
bool recordFlag = false;
File videoFile;
uint32_t frameCount = 0;
const char* videoFileName = "/video.mjpeg";  // ★ 修改扩展名更规范[7](@ref)

// 协议头修正（关键修改）[3,7](@ref)
const char HTTP_HEADER[] = 
  "HTTP/1.1 200 OK\r\n"
  "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n"
  "\r\n";

const char FRAME_BOUNDARY[] = "\r\n--frame\r\n";
const char CONTENT_HEADER[] = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
const char END_BOUNDARY[] = "\r\n--frame--\r\n";

void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  
  // 电源优化[1](@ref)
  WiFi.setTxPower(WIFI_POWER_19_5dBm);
  setCpuFrequencyMhz(240);

  pinMode(CONTROL_PIN, OUTPUT);
  digitalWrite(CONTROL_PIN, LOW);

  // 摄像头初始化（关键参数优化）[3,9](@ref)
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 10 * 1000 * 1000;  // ★ 降低时钟频率提高稳定性[9](@ref)
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_QVGA;     // 强制使用320x240
  config.jpeg_quality = 15;               // ★ 提高画质（值越小质量越高）
  config.fb_count = 1;                    // ★ 单缓冲减少内存占用
  config.fb_location = CAMERA_FB_IN_PSRAM;

  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("摄像头初始化失败 0x%x", err);
    ESP.restart();
  }

  // WiFi连接优化[1](@ref)
  WiFi.mode(WIFI_STA);
  WiFi.setSleep(false);
  WiFi.begin(ssid, password);
  unsigned long wifiTimeout = millis() + 10000;
  while (WiFi.status() != WL_CONNECTED && millis() < wifiTimeout) {
    delay(200);
    Serial.print(".");
  }
  if(WiFi.status() == WL_CONNECTED){
    Serial.printf("\nWiFi已连接 RSSI:%ddB\n", WiFi.RSSI());
    Serial.print("IP地址: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWiFi连接超时");
  }

  // UDP初始化
  udp.begin(targetPort);
  udpControl.begin(CONTROL_PORT);

  // SD卡初始化（增加重试机制）[4](@ref)
  for(int i=0; i<3; i++){
    if(SD_MMC.begin("/sdcard", true)){
      uint8_t cardType = SD_MMC.cardType();
      if(cardType != CARD_NONE){
        Serial.printf("SD卡初始化成功 类型:%s 容量:%.2fGB\n",
          (cardType == CARD_MMC) ? "MMC" :
          (cardType == CARD_SD) ? "SDSC" :
          (cardType == CARD_SDHC) ? "SDHC" : "UNKNOWN",
          SD_MMC.cardSize()/(1024.0 * 1024 * 1024));
        break;
      }
    }
    delay(500);
  }

    // SD卡初始化成功后添加
  if(SD_MMC.cardType() != CARD_NONE){
    checkStorageSpace();       // 开机空间检查
    autoCreateNewFile();       // 自动创建首个文件
  }

}
// 新增存储管理函数（网页5/6）
void checkStorageSpace() {
  if(millis() - lastDeleteCheck < 60000) return; // 每分钟检查一次
  lastDeleteCheck = millis();
  
  uint64_t freeSpace = (SD_MMC.totalBytes() - SD_MMC.usedBytes()) / (1024 * 1024);
  if(freeSpace > MIN_FREE_SPACE) return;

  // 获取文件列表并按时间排序（网页6）
  File root = SD_MMC.open("/");
  struct FileInfo { String name; time_t time; };
  FileInfo files[MAX_FILES];
  int count = 0;
  
  while(File entry = root.openNextFile()) {
    if(count < MAX_FILES && !entry.isDirectory()) {
      files[count].name = entry.name();
      files[count].time = entry.getLastWrite();
      count++;
    }
    entry.close();
  }
  root.close();

  // 冒泡排序旧文件优先（网页6）
  for(int i=0; i<count-1; i++){
    for(int j=i+1; j<count; j++){
      if(files[i].time > files[j].time){
        FileInfo temp = files[i];
        files[i] = files[j];
        files[j] = temp;
      }
    }
  }

  // 删除最早文件（网页5）
  for(int i=0; i<count; i++){
    SD_MMC.remove(files[i].name.c_str());
    freeSpace = (SD_MMC.totalBytes() - SD_MMC.usedBytes())/(1024 * 1024);
    Serial.printf("已删除:%s 剩余空间:%.2fMB\n", files[i].name.c_str(), freeSpace);
    if(freeSpace >= MIN_FREE_SPACE) break;
  }
}

// 新增文件名生成（网页3/7）
String generateFilename() {
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    return "/video_"+String(millis())+".mjpeg";
  }
  
  char buffer[30];
  strftime(buffer, sizeof(buffer), "/video_%Y%m%d_%H%M%S", &timeinfo);
  return String(buffer)+"_"+String(segmentIndex++)+".mjpeg";
}

void autoCreateNewFile() {
  checkStorageSpace();
  currentFileName = generateFilename();
  videoFile = SD_MMC.open(currentFileName.c_str(), FILE_WRITE);
  if(videoFile) {
    videoFile.write((uint8_t*)HTTP_HEADER, strlen(HTTP_HEADER));
    videoFile.write((uint8_t*)FRAME_BOUNDARY, strlen(FRAME_BOUNDARY));
    recordFlag = true;
    segmentStartTime = millis();  // ★ 初始化分段计时
    Serial.printf("自动创建文件:%s\n", currentFileName.c_str());
  }
}


// 帧写入优化（关键修改）[7,10](@ref)
void writeMjpgFrame(camera_fb_t *fb) {
  if(!videoFile || !fb || fb->len < 1024) { // 过滤无效帧
    Serial.println("收到无效帧");
    return;
  }

  char header[64];
  int headerLen = snprintf(header, sizeof(header), CONTENT_HEADER, fb->len);
  
  // 写入帧边界
  if(videoFile.write((uint8_t*)FRAME_BOUNDARY, strlen(FRAME_BOUNDARY)) != strlen(FRAME_BOUNDARY)){
    Serial.println("边界写入失败");
    stopRecording();
    return;
  }
  
  // 写入内容头
  if(videoFile.write((uint8_t*)header, headerLen) != headerLen){
    Serial.println("头信息写入失败");
    stopRecording();
    return;
  }
  
  // 写入JPEG数据
  if(videoFile.write(fb->buf, fb->len) != fb->len){
    Serial.println("图像数据写入失败");
    stopRecording();
    return;
  }

  // 强制每帧刷新[4](@ref)
  videoFile.flush();
  frameCount++;
}

// 停止录制优化[7](@ref)
void stopRecording() {
  if(videoFile) {
    // 写入结束标记
    videoFile.write((uint8_t*)END_BOUNDARY, strlen(END_BOUNDARY));
    
    // 获取文件信息
    uint32_t fileSize = videoFile.size();
    videoFile.close();
    
    Serial.printf("录制完成 帧数:%d 文件大小:%.2fMB\n", 
                 frameCount, fileSize/(1024.0 * 1024));
    frameCount = 0;
  }
  recordFlag = false;
}

void checkControlCommands() {
  char packetBuffer[255];
  int packetSize = udpControl.parsePacket();
  
  if(packetSize) {
    udpControl.read(packetBuffer, packetSize);
    switch(packetBuffer[0]) {
      // case 'r': 
      //   if(!recordFlag) {
      //     SD_MMC.remove(videoFileName);
      //     videoFile = SD_MMC.open(videoFileName, FILE_WRITE);
      //     if(videoFile) {
      //       // 写入完整协议头[7](@ref)
      //       videoFile.write((uint8_t*)HTTP_HEADER, strlen(HTTP_HEADER));
      //       videoFile.write((uint8_t*)FRAME_BOUNDARY, strlen(FRAME_BOUNDARY));
      //       frameCount = 0;
      //       recordFlag = true;
      //       Serial.println("开始MJPG录制");
      //     }
      //   }
      //   break;
              case '1': 
   digitalWrite(CONTROL_PIN, HIGH);
      Serial.println("IO开启");
    break;
            case '0': 
      digitalWrite(CONTROL_PIN, LOW);
      Serial.println("IO关闭");
    break;
        case 'r': 
    if(!recordFlag) autoCreateNewFile();
    break;
         case 's': 
        if(recordFlag) {
          recordFlag = false;
          stopRecording();
          Serial.println("停止录制");
        }
        break;
      case 'v': 
        Serial.println("软件版本信息："+version);
        break;
    }
  }
}




void loop() {

   // 每小时自动分段（网页3）                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
  if(recordFlag && (millis() - segmentStartTime > SEGMENT_DURATION)) { 
    stopRecording();
    autoCreateNewFile();
    segmentStartTime = millis();
  }
  checkControlCommands();

  
  static uint32_t lastFrameTime = 0;
  if(millis() - lastFrameTime < 33) return; // ~30fps
  lastFrameTime = millis();
  
  camera_fb_t *fb = esp_camera_fb_get();
  if(!fb || fb->len < 1024) { // 增加空帧检测
    Serial.println("获取无效帧");
    return;
  }


  if(recordFlag && videoFile) {
    writeMjpgFrame(fb);
  }

  // UDP传输优化（增加超时检测）
  const size_t MTU_SIZE = 1400; // 考虑UDP包头
  size_t remaining = fb->len;
  uint8_t *buffer_ptr = fb->buf;
  unsigned long transferStart = millis();
  
  while(remaining > 0 && (millis() - transferStart < 200)) {
    size_t chunkSize = min(remaining, MTU_SIZE);
    if(udp.beginPacket(targetIP, targetPort)){
      udp.write(buffer_ptr, chunkSize);
      if(!udp.endPacket()){
        Serial.println("UDP发送失败");
      }
      remaining -= chunkSize;
      buffer_ptr += chunkSize;
    }
  }

  esp_camera_fb_return(fb);
  
  // 状态打印优化
  static uint32_t lastStatusTime = 0;
  if(millis() - lastStatusTime > 3000) {
    lastStatusTime = millis();
    Serial.printf("运行状态 | 帧率:%.1f 内存:%dKB SD剩余:%.2fMB\n", 
                  1000.0/(millis()-lastFrameTime), 
                  ESP.getFreeHeap()/1024,
                  (SD_MMC.totalBytes() - SD_MMC.usedBytes())/(1024.0 * 1024));
  }
}


